package com.evan.webadmin.biz.service.impl;

import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.evan.common.core.constant.*;
import com.evan.common.core.object.ResponseResult;
import com.evan.common.core.object.TokenData;
import com.evan.webadmin.biz.dao.ExamMapper;
import com.evan.webadmin.biz.dao.SubjectMapper;
import com.evan.webadmin.biz.dao.SubjectOptionMapper;
import com.evan.webadmin.biz.dto.*;
import com.evan.webadmin.biz.model.*;
import com.evan.webadmin.biz.service.IExamItemService;
import com.evan.webadmin.biz.service.IExamPaperService;
import com.evan.webadmin.biz.service.IExamService;
import com.evan.webadmin.biz.service.ISubjectService;
import com.evan.webadmin.biz.vo.*;
import com.google.common.collect.Lists;
import jodd.util.StringPool;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.servlet.http.HttpServletRequest;
import java.util.*;
import java.util.function.Function;
import java.util.stream.Collectors;

/**
 * <p>
 *  服务实现类
 * </p>
 *
 * @author Pavel
 * @since 2024-06-10
 */
@Service
public class ExamServiceImpl extends ServiceImpl<ExamMapper, Exam> implements IExamService {

    @Autowired
    private ExamMapper examMapper;
    @Autowired
    private IExamItemService examItemService;
    @Autowired
    private ISubjectService subjectService;
    @Autowired
    private SubjectMapper subjectMapper;
    @Autowired
    private SubjectOptionMapper subjectOptionMapper;
    @Autowired
    private IExamPaperService paperService;

    @Override
    public List<Exam> findByCondition(ExamFilter examFilter) {
        QueryWrapper queryWrapper = new QueryWrapper();
        if(examFilter.getExamType() != null){
            queryWrapper.eq("exam_type", examFilter.getExamType());
        }
        if(StringUtils.isNotBlank(examFilter.getUserName())){
            queryWrapper.likeRight("user_name", examFilter.getUserName());
        }
        return examMapper.selectList(queryWrapper);
    }

    @Override
    @Transactional
    public void edit(ExamDto examDto) {
        Exam exam = null;
        if(examDto.getExamId() != null){
            exam = examMapper.selectByExamId(examDto.getExamId());
        }else{
            exam = new Exam();
        }
        exam.setExamType(examDto.getExamType());
        exam.setCorrectCount(examDto.getCorrectCount());
        exam.setPassAble(examDto.getPassAble());
        exam.setScore(examDto.getScore());
        exam.setSubjectCount(examDto.getSubjectCount());
        exam.setUserId(examDto.getUserId());
        exam.setUserName(examDto.getUserName());
        if(examDto.getExamId() != null){
            examMapper.update(exam, new QueryWrapper<Exam>().eq("exam_id", examDto.getExamId()));
        }else{
            examMapper.insert(exam);
        }

        List<ExamItem> examItems = new ArrayList<>();
        for (ExamItemDto examItemDto : examDto.getItems()) {
            ExamItem examItem = new ExamItem();
            examItem.setExamId(exam.getExamId());
            examItem.setCorrectAble(examItemDto.getCorrectAble());
            examItem.setSubjectId(examItemDto.getSubjectId());
            examItem.setUserOption(examItemDto.getUserOption());
            examItems.add(examItem);
        }
        examItemService.saveBatch(examItems);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public ResponseResult record(ExamRecord frontDto, HttpServletRequest request) {
        Exam exam = new Exam();
        exam.setModuleType(frontDto.getModuleType());
        exam.setPaperId(frontDto.getPaperId());
        exam.setSceneType(frontDto.getSceneType());
        exam.setPersonnelType(frontDto.getPersonnelType());
        exam.setExamMode(frontDto.getExamLevel());
        TokenData tokenData = (TokenData) request.getAttribute(TokenData.REQUEST_ATTRIBUTE_NAME);
        exam.setUserId(tokenData.getUserId());
        exam.setUserName(tokenData.getShowName());

        List<Subject> subjects = subjectService.list(frontDto.getPersonnelType(), frontDto.getModuleType(), frontDto.getSceneType());
        if(frontDto.getRecords() != null && subjects != null){
            List<UserAnswerRecord> userAnswerRecords = new ArrayList<>();
            exam.setSubjectCount(frontDto.getRecords().size());
            int correctCount = 0;
            int goalScore = 0;
            Map<Long, Subject> subjectMap = subjects.stream().collect(Collectors.toMap(Subject::getSubjectId, Function.identity()));
            for (SubjectRecord record : frontDto.getRecords()) {
                int default_subjectScore = 3;
                UserAnswerRecord userAnswerRecord = new UserAnswerRecord();
                userAnswerRecord.setSubjectId(record.getSubjectId());
                userAnswerRecord.setAnswer(record.getAnswer().trim());
                if(record.getAnswers() != null && record.getAnswers().size() > 0){
                    String answers = record.getAnswers().stream().sorted().collect(Collectors.joining(StringPool.SLASH));
                    userAnswerRecord.setAnswer(answers);
                }
                Subject subject = subjectMap.get(record.getSubjectId());
                if(subject == null && (StringUtils.isBlank(record.getAnswer())) && record.getAnswers() == null){
                    continue;
                }
                if(record.getSubjectType() == SubjectTypeEnum.MULTI_SELECT.getCode()){
                    if(record.getAnswers() == null){
                        continue;
                    }
                    String answers = record.getAnswers().stream().sorted().collect(Collectors.joining(StringPool.SLASH));
                    //['A','C','D']按字母顺排序
                    if(StringUtils.isBlank(subject.getAnswer())){
                        continue;
                    }
                    String[] corrects = subject.getAnswer().split(StringPool.SLASH);
                    // 使用 Stream 对数组进行排序并连接成一个新的字符串
                    String sortedAnswer = Arrays.stream(corrects).sorted().collect(Collectors.joining(StringPool.SLASH));
                    userAnswerRecord.setAnswer(sortedAnswer);
                    if(sortedAnswer.equalsIgnoreCase(answers)){
                        correctCount++;
                        userAnswerRecord.setCorrectAble(true);
                        if(subject.getSubjectScore() != null && subject.getSubjectScore() > 0){
                            goalScore += subject.getSubjectScore();
                        }else{
                            goalScore += default_subjectScore;
                        }
                    }
                    else{
                        userAnswerRecord.setCorrectAble(false);
                    }
                } else if(record.getSubjectType() == SubjectTypeEnum.FILL_IN.getCode()){
                    if(org.springframework.util.StringUtils.hasLength(record.getAnswer()) &&
                            org.springframework.util.StringUtils.hasLength(subject.getTextAnswer()) &&
                            record.getAnswer().trim().equalsIgnoreCase(subject.getTextAnswer().trim())){
                        correctCount++;
                        userAnswerRecord.setCorrectAble(true);
                        if(subject.getSubjectScore() != null && subject.getSubjectScore() > 0){
                            goalScore += subject.getSubjectScore();
                        }else{
                            goalScore += default_subjectScore;
                        }
                    }else{
                        userAnswerRecord.setCorrectAble(false);
                    }
                } else {
                    if(record.getAnswer().equalsIgnoreCase(subject.getAnswer())){
                        correctCount++;
                        userAnswerRecord.setCorrectAble(true);
                        if(subject.getSubjectScore() != null && subject.getSubjectScore() > 0){
                            goalScore += subject.getSubjectScore();
                        }else{
                            goalScore += default_subjectScore;
                        }
                    }else{
                        userAnswerRecord.setCorrectAble(false);
                    }
                }
                userAnswerRecords.add(userAnswerRecord);
            }
            exam.setUserAnswer(JSONObject.toJSONString(userAnswerRecords));
            exam.setCorrectCount(correctCount);
            exam.setScore(goalScore);
            exam.setExamMode(frontDto.getExamMode());
            if(ModuleTypeEnum.COURSE.getCode() == frontDto.getModuleType()){
                exam.setPassAble(correctCount == exam.getSubjectCount());
                exam.setExamType(ModuleTypeEnum.COURSE.getCode());
                exam.setExamLevel(frontDto.getExamLevel());
            }else{
                ExamPaper examPaper = paperService.findById(frontDto.getPaperId());
                if(examPaper != null){
                    if(goalScore >= examPaper.getPassScore().intValue()){
                        exam.setPassAble(true);
                    }else{
                        exam.setPassAble(false);
                    }
                }else{
                    exam.setPassAble(true);
                }
                exam.setExamType(ModuleTypeEnum.EXAM.getCode());
            }

            exam.setCreateTime(new Date());
        }
        if(examMapper.insert(exam) > 0){
            return ResponseResult.success(exam);
        }
        return ResponseResult.error(ErrorCodeEnum.DATA_SAVE_FAILED);
    }

    @Override
    public ResponseResult<Exam> exist(ExamDtoFilter filter, HttpServletRequest request) {
        ExamPaper publishedPaper = null;
        TokenData tokenData = (TokenData) request.getAttribute(TokenData.REQUEST_ATTRIBUTE_NAME);
        if(ModuleTypeEnum.EXAM.getCode() == filter.getModuleType()){
            publishedPaper = paperService.findPublishedPaper(filter.getPersonnelType(), filter.getModuleType());
            if(publishedPaper == null){
                return ResponseResult.success(null);
            }
        }else if(ModuleTypeEnum.COURSE.getCode() == filter.getModuleType()){
            QueryWrapper<Exam> queryWrapper = new QueryWrapper<Exam>();
            queryWrapper.eq("user_id", tokenData.getUserId());
            queryWrapper.eq("module_type", filter.getModuleType());
            queryWrapper.eq("scene_type", filter.getSceneType());
            queryWrapper.eq("pass_able", true);
            if(SubjectLevelEnum.MIDDLE.getCode() == filter.getExamLevel()){
                queryWrapper.eq("exam_level", SubjectLevelEnum.PRIMARY.getCode());
                Long count = examMapper.selectCount(queryWrapper);
                if(count == 0){
                    return ResponseResult.error(ErrorCodeEnum.REQUIRE_PRIMARY_EXAM);
                }
            }else if(SubjectLevelEnum.SENIOR.getCode() == filter.getExamLevel()){
                queryWrapper.eq("exam_level", SubjectLevelEnum.MIDDLE.getCode());
                Long count = examMapper.selectCount(queryWrapper);
                if(count == 0){
                    return ResponseResult.error(ErrorCodeEnum.REQUIRE_MIDDLE_EXAM);
                }
            }
        }

        QueryWrapper<Exam> queryWrapper = new QueryWrapper<Exam>();
        queryWrapper.eq("user_id", tokenData.getUserId());
        queryWrapper.eq("module_type", filter.getModuleType());
        if(ModuleTypeEnum.COURSE.getCode() == filter.getModuleType()){
            queryWrapper.eq("scene_type", filter.getSceneType());
            queryWrapper.eq("exam_level", filter.getExamLevel());
            queryWrapper.eq("pass_able", true);
        }
        if(ModuleTypeEnum.EXAM.getCode() == filter.getModuleType()){
            queryWrapper.eq("exam_mode", ExamModeEnum.EXAM.getType());
            queryWrapper.eq("paper_id", publishedPaper.getPaperId());
        }
        queryWrapper.orderByDesc("create_time");
        List<Exam> exams = examMapper.selectList(queryWrapper);
        return ResponseResult.success((exams == null || exams.size() == 0) ? null: exams.get(0));
    }

    @Override
    public ResponseResult<ExamFrontVo> recordDetail(ExamDtoFilter filter, HttpServletRequest request) {
        ExamFrontVo examFrontVo = new ExamFrontVo();
        String userId = filter.getSelectUserId();
        if(StringUtils.isBlank(userId)){
            TokenData tokenData = (TokenData) request.getAttribute(TokenData.REQUEST_ATTRIBUTE_NAME);
            userId = tokenData.getUserId();
        }
        QueryWrapper queryWrapper = new QueryWrapper();
        queryWrapper.eq("user_id", userId);
        queryWrapper.eq("module_type", filter.getModuleType());
        if(ModuleTypeEnum.COURSE.getCode() == filter.getModuleType()){
            queryWrapper.eq("exam_level", filter.getExamLevel());
            queryWrapper.eq("pass_able", true);
        }
        if(filter.getModuleType() == ModuleTypeEnum.EXAM.getCode() && ExamModeEnum.EXAM.getType() == filter.getExamMode()){
            Long paperId = filter.getSelectPaperId();
            if(paperId == null){
                ExamPaper publishedPaper = paperService.findPublishedPaper(filter.getPersonnelType(), filter.getModuleType());
                paperId = publishedPaper.getPaperId();
                examFrontVo.setPaperName(publishedPaper.getPaperName());
            }
            if(paperId != null){
                queryWrapper.eq("paper_id", paperId);
            }
        }
        queryWrapper.orderByDesc("create_time");
        List<Exam> exams = examMapper.selectList(queryWrapper);
        if(CollectionUtils.isNotEmpty(exams)){
            Exam exam = exams.get(0);
            examFrontVo.setExamId(exam.getExamId());
            examFrontVo.setExamType(exam.getExamType());
            examFrontVo.setPersonnelType(exam.getPersonnelType());
            examFrontVo.setModuleType(exam.getModuleType());
            examFrontVo.setScore(exam.getScore());
            examFrontVo.setSceneType(exam.getSceneType());
            examFrontVo.setCorrectCount(exam.getCorrectCount());
            examFrontVo.setSubjectCount(exam.getSubjectCount());
            examFrontVo.setUserId(exam.getUserId());
            examFrontVo.setUserName(exam.getUserName());
            String userAnswer = exam.getUserAnswer();
            if(StringUtils.isNotBlank(userAnswer)){
                List<UserAnswerRecord> answerRecords = JSONArray.parseArray(userAnswer, UserAnswerRecord.class);
                //获取UserAnswerRecord subjectId字段的list
                List<Long> subjectIds = answerRecords.stream().map(UserAnswerRecord::getSubjectId).collect(Collectors.toList());
                //根据subjectId查询题目
                QueryWrapper<Subject> subjectQueryWrapper = new QueryWrapper<>();
                subjectQueryWrapper.in("subject_id", subjectIds);
                List<Subject> subjects = subjectMapper.selectList(subjectQueryWrapper);
                //subjects 转map subjectid为key 对象为值
                Map<Long, Subject> subjectMap = subjects.stream().collect(Collectors.toMap(Subject::getSubjectId, Function.identity()));
                //将题目和用户答案记录合并
                QueryWrapper<SubjectOption> subjectOptionQueryWrapper = new QueryWrapper<>();
                subjectOptionQueryWrapper.in("subject_id", subjectIds);
                List<SubjectOption> examList = subjectOptionMapper.selectList(subjectOptionQueryWrapper);
                //examList 以subjectId分组 得到subjectId为key List为值
                Map<Long, List<SubjectOption>> subjectOptionMap = examList.stream().collect(Collectors.groupingBy(SubjectOption::getSubjectId));
                List<SubjectFrontVo> subjectFrontVos = new ArrayList<>();
                for (UserAnswerRecord record : answerRecords) {
                    Subject subject = subjectMap.get(record.getSubjectId());
                    List<SubjectOption> options = subjectOptionMap.get(record.getSubjectId());
                    SubjectFrontVo subjectFrontVo = new SubjectFrontVo();
                    subjectFrontVo.setSubjectId(record.getSubjectId());
                    subjectFrontVo.setSubjectTitle(subject.getSubjectTitle());
                    subjectFrontVo.setSubjectScore(subject.getSubjectScore());
                    subjectFrontVo.setSubjectType(subject.getSubjectType());
                    subjectFrontVo.setCorrectAnswer(subject.getAnswer());
                    subjectFrontVo.setAnswer(record.getAnswer());
                    if(subject.getSubjectType() == SubjectTypeEnum.MULTI_SELECT.getCode()){
                        if(StringUtils.isNotBlank(record.getAnswer())){
                            subjectFrontVo.setAnswers(Arrays.asList(record.getAnswer().split(StringPool.SLASH)));
                        }
                    } else if(subject.getSubjectType() == SubjectTypeEnum.FILL_IN.getCode()){
                        subjectFrontVo.setTextAnswer(subject.getTextAnswer());
                    }
                    if(subject.getSubjectType() != SubjectTypeEnum.FILL_IN.getCode()){
                        List<SubjectOptionFrontVo> optionFrontVos = new ArrayList<>();
                        for (SubjectOption option : options) {
                            SubjectOptionFrontVo subjectOptionFrontVo = new SubjectOptionFrontVo();
                            subjectOptionFrontVo.setSubjectId(option.getSubjectId());
                            subjectOptionFrontVo.setOptionContent(option.getOptionContent());
                            subjectOptionFrontVo.setOptionTitle(option.getOptionTitle());
                            subjectOptionFrontVo.setOptionId(option.getOptionId());
                            optionFrontVos.add(subjectOptionFrontVo);
                        }
                        subjectFrontVo.setOptions(optionFrontVos);
                    }
                    subjectFrontVos.add(subjectFrontVo);
                }
                examFrontVo.setSubjects(subjectFrontVos);
                return ResponseResult.success(examFrontVo);
            }
        }
        return ResponseResult.success(null);
    }

    @Override
    public ResponseResult<List<ExamRankVo>> rank(ExamDtoFilter filter) {
        ExamPaper paper = paperService.findPublishedPaper(filter.getPersonnelType(), filter.getModuleType());
        if(paper == null){
            return ResponseResult.success(Lists.newArrayList());
        }
        List<ExamRankVo> examRankVos = new ArrayList<>();
        examRankVos = examMapper.rank10(filter.getModuleType(), paper.getPaperId(), filter.getPersonnelType());
//        QueryWrapper wrapper = new QueryWrapper();
//        if(filter.getModuleType() != null){
//            wrapper.eq("module_type", filter.getModuleType());
//        }
//        if(filter.getPersonnelType() != null){
//            wrapper.eq("personnel_type", filter.getPersonnelType());
//        }
//        wrapper.eq("paper_id", paper.getPaperId());
//        wrapper.orderByDesc("score");
//        wrapper.last("LIMIT 10");
//        List<Exam> exams = examMapper.selectList(wrapper);
//        List<ExamRankVo> examRankVos = new ArrayList<>();
//        if(!org.springframework.util.CollectionUtils.isEmpty(exams)){
//            int pos = 0;
//            for (Exam exam: exams) {
//                ExamRankVo rankVo = new ExamRankVo();
//                rankVo.setUserName(exam.getUserName());
//                rankVo.setScore(exam.getScore());
//                rankVo.setRank(++pos);
//                examRankVos.add(rankVo);
//            }
//        }
        return ResponseResult.success(examRankVos);
    }

    @Override
    public ResponseResult<ExamRankVo> rankSelf(ExamDtoFilter filter, HttpServletRequest request) {
        ExamPaper paper = paperService.findPublishedPaper(filter.getPersonnelType(), filter.getModuleType());
        if(paper == null){
            return ResponseResult.success(new ExamRankVo());
        }
        TokenData tokenData = (TokenData) request.getAttribute(TokenData.REQUEST_ATTRIBUTE_NAME);
        ExamRankVo examRankVo = examMapper.rankSelf(filter.getModuleType(), paper.getPaperId(), filter.getPersonnelType(), tokenData.getUserId());
//        ExamRankVo rankVo = new ExamRankVo();
//        QueryWrapper wrapper = new QueryWrapper();
//        if(filter.getModuleType() != null){
//            wrapper.eq("module_type", filter.getModuleType());
//        }
//        if(filter.getPersonnelType() != null){
//            wrapper.eq("personnel_type", filter.getPersonnelType());
//        }
//        wrapper.eq("paper_id", paper.getPaperId());
//        wrapper.orderByDesc("score");
//        List<Exam> exams = examMapper.selectList(wrapper);
//        TokenData tokenData = (TokenData) request.getAttribute(TokenData.REQUEST_ATTRIBUTE_NAME);
//        if(!org.springframework.util.CollectionUtils.isEmpty(exams)){
//           List<String> userIds = exams.stream().map(Exam::getUserId).collect(Collectors.toList());
//           if(userIds.contains(tokenData.getUserId())){
//                int pos = userIds.indexOf(tokenData.getUserId());
//                rankVo.setRank(pos + 1);
//                rankVo.setUserName(exams.get(pos).getUserName());
//                rankVo.setScore(exams.get(pos).getScore());
//           }
//        }
//        rankVo.setPaperName(paper.getPaperName());
        return ResponseResult.success(examRankVo);
    }

    @Override
    public List<ExamRankVo> rankList(ExamDtoFilter filter) {
        return examMapper.rankList(filter.getModuleType(), filter.getSelectPaperId(), filter.getPersonnelType());
    }

    @Override
    public List<ExamVo> listByCondition(Integer examType, String userName) {
        return examMapper.listByCondition(examType, userName);
    }

    @Override
    public long existExam(long paperId) {
        return examMapper.selectCount(new QueryWrapper<Exam>().eq("paper_id", paperId));
    }
}
